package com.sndscl.rpc.call;

import com.sndscl.rpc.common.dto.RpcRequest;
import com.sndscl.rpc.common.dto.RpcResponse;
import com.sndscl.rpc.common.exception.ServerResponseTimeOut;
import com.sndscl.rpc.common.util.ClazzInvockUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author lsh
 * @Date 2020/8/11 16:14
 **/
public class RpcCallInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class declarClazz = method.getDeclaringClass();
        String methodSign = ClazzInvockUtil.getMethodSign(declarClazz,method);
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setType("01");
        rpcRequest.setId(UUID.randomUUID().toString());
        rpcRequest.setClassName(declarClazz.getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setParameterTypes(method.getParameterTypes());
        rpcRequest.setArgs(args);
        rpcRequest.setMethodSign(methodSign);
        RpcRequestWarp rpcRequestWarp = new RpcRequestWarp(rpcRequest);
        return rpcCall(rpcRequestWarp);
    }

    public Object rpcCall(RpcRequestWarp rpcRequestWarp) throws Throwable{
        //请求超过两次抛出异常，结束请求
        int num = rpcRequestWarp.getFailNum();
        if( num >= 2){
            throw  new ServerResponseTimeOut();
        }
        RpcRequest rpcRequest = rpcRequestWarp.getRpcRequest();
        String id = rpcRequest.getId();
        id = id + "_" + num;
        rpcRequest.setId(id);
        SynchronousQueue<RpcResponse> synchronousQueue = new SynchronousQueue();
        SndSclCall.synchronousQueueMap.put(id,synchronousQueue);
        NettyClient nettyClient = SndSclCall.rpcCall(rpcRequestWarp);
        if(nettyClient == null){
            System.out.println("NOT FOUND REMOTE INTERFACE.");
            throw new RuntimeException();
        }
        //TODO 超时时间可配置
        RpcResponse rpcResponse = synchronousQueue.poll(10, TimeUnit.SECONDS);
        //移除队列
        SndSclCall.synchronousQueueMap.remove(id);
        if(rpcResponse == null){
            //请求超时
            System.out.println("SNDSCL CALL ERROR : server time out...");
            rpcRequestWarp.addFailClient(nettyClient);
            //超时重试
            rpcCall(rpcRequestWarp);
        }else{
            int retCode = rpcResponse.getRetCode();
            if( retCode == 200){
                return rpcResponse.getResult();
            }else{
                System.out.println("SNDSCL CALL ERROR CODE:"+retCode);
                throw new RuntimeException();
            }
        }
        return null;
    }

}
